﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Data;
using System.Xml.Linq;
using System.IO;
using System.Web;
using AppEntity;

namespace AppEntity
{
    public partial class App
    {
        public class Entity
        {
            internal XmlDocument AppDom;
            internal App App;
            internal Common.DataBase.Sqlite Sqlite = null;

            public XmlDocument EntityDom
            {
                get
                {
                    return Base.GetEntitySetting(this.AppID, this.ID);
                }
            }
            public string AppID;
            public string ID;
            public string Name;
            public DateTime DateCreated
            {
                get { return this.AppDom.SelectSingleNode("/root/entities/entity[@name='" + this.ID + "']/@datecreated").Value.ToDateTime(); }                  
            }
            public string GetName(string Lang)
            {
                XmlNode Attr = this.AppDom.SelectSingleNode("/root/entities/entity[@name='" + this.ID + "']/@*[name()='" + Lang + "']");
                if (Attr == null) return string.Empty;
                return Attr.Value;
            }

            public Column[] Columns
            {
                get
                {
                    XmlNodeList Nodes = this.EntityDom.SelectNodes("/root/app/entity/columns/node");
                    int Len = Nodes.Count;
                    Column[] Cols = new Column[Len];
                    for (int i = 0; i < Len; i++)
                    {
                        Cols[i] = new Column();
                        Cols[i].Name = Nodes[i].GetAttribute("name");
                        Cols[i].DefaultValue = Nodes[i].GetAttribute("default");
                        Cols[i].Type = App.Column.ParseColumnType(Nodes[i].GetAttribute("type"));
                        Cols[i].Title = Nodes[i].GetAttribute("title");
                        Cols[i].IsCore = Nodes[i].GetAttribute("core")=="1" ? true : false;
                        Cols[i].Control = Nodes[i].GetAttribute("control");
                        Cols[i].App = this.App;
                        Cols[i].Entity = this;
                    }
                    return Cols;
                }
            }

            public Entity(string EntityID)
            {                
            }

            public XmlDocument GetCatDom()
            {
                string[] CatColumns = new string[] { "id", "name", "detail", "status", "private", "userid", "sort", "parentid", "datecreated" };

                System.Data.DataTable Dt = this.App.Sqlite.GetDataTable("SELECT "+CatColumns.Join(",")+" FROM [Entity-"+this.ID+"-Category]");
                StringBuilder sb = new StringBuilder();
                XmlWriterSettings Settings = new XmlWriterSettings();
                Settings.Encoding = Encoding.UTF8;
                XmlWriter Writer = XmlWriter.Create(sb, Settings);
                Writer.WriteStartElement("root");
                
                foreach (System.Data.DataRow Row in Dt.Rows)
                {
                    Writer.WriteStartElement("cat");
                    foreach(string Column in CatColumns)
                    {
                        Writer.WriteAttributeString(Column, Row[Column].ToString());
                    }
                    Writer.WriteEndElement();                    
                }
                Writer.WriteEndElement();
                Dt.Dispose();
                XmlDocument dom = new XmlDocument();
                dom.LoadXml(sb.ToString());
                dom.DocumentElement.AppendChild(dom.SelectSingleNode("/root/cat[@id='0']"));
                XmlNodeList Cats = dom.SelectNodes("/root/cat");
                foreach (XmlNode Cat in Cats)
                {
                    XmlNode ParNode = Cat.SelectSingleNode("@parentid");
                    if (ParNode == null) continue;
                    string Pid = ParNode.Value;
                    if (string.IsNullOrEmpty(Pid))
                    {
                        dom.DocumentElement.AppendChild(Cat);
                    }
                    else
                    {
                        dom.SelectSingleNode("//cat[@id='{0}']", Pid).AppendChild(Cat);
                    }
                }
                //TODO:实现分类排序，根据特殊字段 sort

                return dom;
            }

            public string GetDataListToXmlString(List<int> PrimaryKeys, IList<string> ColumnsName, int PageSize, int Page)
            {
                DataTable Dt = GetDataTable(PrimaryKeys, ColumnsName, PageSize, Page);
                StringBuilder sb = new StringBuilder();
                XmlWriterSettings Settings = new XmlWriterSettings();
                Settings.Encoding = Encoding.UTF8;
                XmlWriter Writer = XmlWriter.Create(sb, Settings);
                Writer.WriteStartElement("root");                
                DataRowCollection Rows = Dt.Rows;
                int Total = Rows.Count;
                Writer.WriteAttributeString("total", Total.ToString());
                Writer.WriteAttributeString("pagesize", PageSize.ToString());
                Writer.WriteAttributeString("page", Page.ToString());
                Writer.WriteAttributeString("totalpage", Math.Ceiling((double)Total / (double)PageSize).ToString());
                int ColLen = Dt.Columns.Count;
                DataColumn[] Columns = new DataColumn[ColLen];
                for (int i = 0; i < ColLen; i++)
                {
                    Columns[i] = Dt.Columns[i];
                }
                foreach (DataRow Dr in Rows)
                {
                    Writer.WriteStartElement("item");
                    foreach (DataColumn Col in Columns)
                    {
                        Writer.WriteAttributeString(Col.ColumnName, Dr[Col].ToString());
                    }
                    Writer.WriteEndElement();
                }
                Writer.WriteEndElement();
                Writer.Close();
                Dt.Dispose();                
                return sb.ToString();
            }

            public string GetDataListToXmlString()
            { 
                return GetDataListToXmlString(GetPrimaryKeys(), null, 15, 1);
            }

            public string GetDataListToXmlString(int PageSize, int Page)
            {
                return GetDataListToXmlString(GetPrimaryKeys(), null, PageSize, Page);
            }

            public XDocument GetDataDetailToXmlString(string RecordID)
            {
                DataRow Dr = GetDataRow(RecordID);
                XDocument xdom = GetEmptyRecordXml();
                xdom.Element("root").Element("app").Element("entity").Elements().Each(n =>
                    {
                        object Field = Dr[n.Name.ToString()];
                        if (Field != null)
                        {
                            n.Value = Field.ToString();
                        }
                    });
                return xdom;
            }

            public DataRow GetDataRow(string RecordID)
            {                
                AppEntity.Common.DataBase.Sqlite Sqlite = this.Sqlite;
                DataTable Dt = Sqlite.GetDataTable("SELECT * FROM [Entity-" + this.ID + "-Data] WHERE id=" + RecordID);
                if (Dt == null) return null;
                return Dt.Rows[0];
            }

            /// <summary>
            /// 返回 data 的xml结构
            /// </summary>
            /// <returns></returns>
            public XDocument GetEmptyRecordXml()
            {                
                XElement Entity = new XElement("entity", new XAttribute("name", this.ID));
                XmlDocument Settings = this.EntityDom;
                Settings.SelectNodes("/root/app/entity/columns/node").Each(n => 
                {
                    Entity.Add(new XElement(n.GetAttribute("name")));
                });
                XDocument xdom = XDocument.Load(new StringReader("<?xml version='1.0' encoding='utf-8'?><root/>"));
                xdom.Add(new XElement("app", new XAttribute("name", this.AppID), Entity));
                return xdom;
            }

            public DataTable GetDataTable(List<int>IDArray, IList<string> ColumnsName, int PageSize, int Page)
            {
                AppEntity.Common.DataBase.Sqlite Sqlite = this.Sqlite;               
                string Columns = "*";
                if (ColumnsName != null && ColumnsName.Count()>0)
                {
                    Columns = ColumnsName.ToArray().Join(",");
                }
                if (Page < 1) Page = 1;
                if (PageSize < 0) PageSize = 15;
                int[] IDList = GetPrimaryKeys().Skip(Page * PageSize).Take(PageSize).ToArray();
                string[] IDStr = new string[IDArray.Count];
                for(int i=0; i<IDStr.Length; i++)
                {
                    IDStr[i] = IDArray[i].ToString();
                }
                DataTable Dt = Sqlite.GetDataTable("SELECT " + Columns + " FROM [Entity-" + this.ID + "-Data] WHERE id in ("+IDStr.Join(",")+")");            
                return Dt;
            }

            /// <summary>
            /// 从缓存中按顺序获取所有id的数组。
            /// </summary>
            /// <returns></returns>
            public List<int> GetPrimaryKeys()
            {
                string CacheKey = "Entity-" + this.ID + "-PrimaryKeys";
                if (HttpRuntime.Cache[CacheKey] != null)
                {
                    return (List<int>)HttpRuntime.Cache[CacheKey];
                }

                AppEntity.Common.DataBase.Sqlite Sqlite = this.Sqlite;
                DataTable Dt = Sqlite.GetDataTable("SELECT id FROM [Entity-"+this.ID+"-Data]");
                int Total = Dt.Rows.Count;
                List<int> List = new List<int>(Total);
                for (int i = 0; i < Total; i++)
                {
                    List[i] = Dt.Rows[i][0].ToString().ToInt32(0);
                }
                HttpRuntime.Cache.Insert(CacheKey, List, null, DateTime.Now.AddHours(1), System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.AboveNormal, null);
                return List;
            }

            public List<int> GetUserDataIds(string UserID)
            {
                DataTable Dt = this.Sqlite.GetDataTable("SELECT id FROM [Entity-" + this.ID + "-Data] WHERE userid='"+UserID+"'");
                return GetIdsColumn(Dt);
            }

            public List<int> GetDataIdsBetweenDates(string BeginDate, string EndDate)
            {
                DataTable Dt = this.Sqlite.GetDataTable("SELECT id FROM [Entity-" + this.ID + "-Data] WHERE datecreated BETWEEN datetime('" + BeginDate + "') AND datetime('" + EndDate + "')");
                return GetIdsColumn(Dt);
            }

            public List<int> GetCatDataIds(int CatID)
            {
                DataTable Dt = this.Sqlite.GetDataTable("SELECT id FROM [Entity-" + this.ID + "-Data] where catid=" + CatID);
                return GetIdsColumn(Dt);
            }

            private List<int> GetIdsColumn(DataTable Dt)
            {
                int Len = Dt.Rows.Count;
                List<int> List = new List<int>(Len);
                foreach (DataRow Dr in Dt.Rows)
                {
                    List.Add(Dr[0].ToString().ToInt32(0));
                }
                Dt.Dispose();
                return List;
            }

            public Record CreateRecord()
            {
                Record Re = new Record();
                Re.Sqlite = this.Sqlite;
                Re.AppDom = this.AppDom;
                Re.App = this.App;
                Re.EntityDom = this.EntityDom;
                Re.Entity = this;
                return Re;
            }

            public Record GetRecord(string ID)
            {                                
                DataRow Dr = GetDataRow(ID);
                if (Dr == null) return null;
                Record Re = new Record();
                DataTable Dt = Dr.Table;
                foreach (DataColumn Dc in Dt.Columns)
                {
                    Re.SetColumnValue(Dc.ColumnName, Dr[Dc]);
                }
                return Re;
            }

            public XDocument GetRecordXml(string ID)
            {
                DataTable Dt = this.Sqlite.GetDataTable("SELECT * [Entity-" + this.ID + "-Data] WHERE id=" + ID);
                if (Dt.Rows.Count == 0) return null;
                DataRow Dr = Dt.Rows[0];
                XDocument xdom = GetEmptyRecordXml();
                HashSet<string> Cols = new HashSet<string>();
                foreach (DataColumn Dc in Dt.Columns)
                {
                    Cols.Add(Dc.ColumnName);
                }
                xdom.Element("root").Element("app").Element("entity").Elements().Each(n =>                 
                {
                    string ColName = n.Name.ToString();
                    if (Cols.Contains(ColName))
                    {
                        n.Value = Dr[ColName].ToString();
                    }                    
                });                
                return xdom;
            }

            public void Remove(string[] ID)
            {
                if (ID == null || ID.Length == 0) return;
                this.Sqlite.ExecuteSql("DELETE FROM [Entity-" + this.ID + "-Data] WHERE id in (" + ID.Join(",") + ")");
            }
            public void Remove(int ID)
            {
                if (ID == null || ID<=0) return;
                this.Sqlite.ExecuteSql("DELETE FROM [Entity-" + this.ID + "-Data] WHERE id="+ID);
            }
            public void Remove(string ID)
            {
                if (ID == null || ID.Length==0) return;
                ID = ID.ToInt32(0).ToString();
                if (ID == "0") return;
                this.Sqlite.ExecuteSql("DELETE FROM [Entity-" + this.ID + "-Data] WHERE id=" + ID);
            }
        }

        
    }
}
